using System;
using System.Net;
using MbUnit.Framework;
using Rhino.Mocks;
using Subkismet;

namespace UnitTests.Subkismet
{
	[TestFixture]
	public class AkismetTests
	{
		//Used for testing purporses.
		public interface IFakeComment
		{
			string AuthorUserAgent { get;}
			IPAddress IpAddress { get;}

		}

		private Converter<IFakeComment, Comment> commentConverter = delegate(IFakeComment comment) { return new Comment(comment.IpAddress, comment.AuthorUserAgent); };
		
		[Test]
		public void CanInstantiate()
		{
			Akismet<IFakeComment> service = new Akismet<IFakeComment>("api-key", new Uri("http://localhost:2072"), this.commentConverter);
			Assert.IsNotNull(service);
		}

		[Test]
		public void CanVerifyApiKey()
		{
			IAkismetClient akismetClient;

			MockRepository mocks = new MockRepository();
			using(mocks.Record())
			{
				akismetClient = mocks.CreateMock<IAkismetClient>();
				Expect.Call(akismetClient.VerifyApiKey()).Return(true);
				Expect.Call(akismetClient.Proxy).PropertyBehavior();
			}
			using (mocks.Playback())
			{
				Akismet<IFakeComment> service = new Akismet<IFakeComment>(akismetClient, commentConverter);
				Assert.IsTrue(service.VerifyApiKey());
			}
		}

		[Test]
		[ExpectedException(typeof(WebException))]
		public void VerifyApiKeyThrowsWebExceptionThrown()
		{
			IAkismetClient akismetClient;
			MockRepository mocks = new MockRepository();
			using(mocks.Record())
			{
				akismetClient = mocks.CreateMock<IAkismetClient>();
				Expect.Call(akismetClient.VerifyApiKey()).Throw(new WebException());
				Expect.Call(akismetClient.Proxy).PropertyBehavior();
			}

			using (mocks.Playback())
			{
				Akismet<IFakeComment> service = new Akismet<IFakeComment>(akismetClient, commentConverter);
				service.VerifyApiKey();
			}
		}

		[Test]
		public void IsSpamReturnsTrueForSpam()
		{
		    MockRepository mocks = new MockRepository();
			IAkismetClient akismetClient;
			IFakeComment myComment;
			IPAddress ip = IPAddress.Parse("127.0.0.1");

			using(mocks.Record())
			{
				myComment = SetupFakeComment(mocks, ip);

				akismetClient = mocks.CreateMock<IAkismetClient>();
				IComment comment = mocks.CreateMock<IComment>();
				Expect.Call(akismetClient.Proxy).PropertyBehavior();
				Expect.Call(akismetClient.CheckCommentForSpam(comment)).Return(true).IgnoreArguments();
				akismetClient.SubmitSpam(null);
				LastCall.IgnoreArguments();
			}

			Akismet<IFakeComment> service = new Akismet<IFakeComment>(akismetClient, commentConverter);
			Assert.IsTrue(service.IsSpam(myComment));
		}

		[Test]
		public void IsSpamReturnsFalseIfAkismetClientDoesSo()
		{
			MockRepository mocks = new MockRepository();
			IAkismetClient akismetClient;
			IFakeComment myComment;
			IPAddress ip = IPAddress.Parse("127.0.0.1");

			using (mocks.Record())
			{
				myComment = SetupFakeComment(mocks, ip);

				akismetClient = mocks.CreateMock<IAkismetClient>();
				IComment comment = mocks.CreateMock<IComment>();
				Expect.Call(akismetClient.Proxy).PropertyBehavior();
				Expect.Call(akismetClient.CheckCommentForSpam(comment)).Return(false).IgnoreArguments();
			}

			Akismet<IFakeComment> service = new Akismet<IFakeComment>(akismetClient, commentConverter);
			Assert.IsFalse(service.IsSpam(myComment));
		}

		[Test]
        [ExpectedException(typeof(InvalidResponseException))]
		public void IsSpamThrowsInvalidResponseException()
		{
			IAkismetClient akismetClient;
			IFakeComment myComment;
			MockRepository mocks = new MockRepository();
			IPAddress ip = IPAddress.Parse("127.0.0.1");

			using(mocks.Record())
			{
				myComment = SetupFakeComment(mocks, ip);

				akismetClient = mocks.CreateMock<IAkismetClient>();
				IComment comment = mocks.CreateMock<IComment>();
				Expect.Call(akismetClient.Proxy).PropertyBehavior();
				Expect.Call(akismetClient.CheckCommentForSpam(comment)).Throw(new InvalidResponseException()).IgnoreArguments();
			}

			Akismet<IFakeComment> service = new Akismet<IFakeComment>(akismetClient, commentConverter);
			service.IsSpam(myComment);
		}

		[Test]
        public void CanSubmitSpam()
		{
			IAkismetClient akismetClient;
			IFakeComment myComment;
			MockRepository mocks = new MockRepository();
			IPAddress ip = IPAddress.Parse("127.0.0.1");

			using(mocks.Record())
			{
				myComment = SetupFakeComment(mocks, ip);

				akismetClient = mocks.CreateMock<IAkismetClient>();
				IComment comment = mocks.CreateMock<IComment>();
				Expect.Call(akismetClient.Proxy).PropertyBehavior();
				akismetClient.SubmitSpam(comment);
				LastCall.IgnoreArguments();
			}

			using(mocks.Playback())
			{
				Akismet<IFakeComment> service = new Akismet<IFakeComment>(akismetClient, commentConverter);
				service.SubmitSpam(myComment);
			}
		}

		[Test]
        public void CanSubmitGoodFeedback()
		{
            IAkismetClient akismetClient;
			IFakeComment myComment;
			MockRepository mocks = new MockRepository();
			IPAddress ip = IPAddress.Parse("127.0.0.1");

			using(mocks.Record())
			{
				myComment = SetupFakeComment(mocks, ip);

				akismetClient = mocks.CreateMock<IAkismetClient>();
				IComment comment = mocks.CreateMock<IComment>();
				Expect.Call(akismetClient.Proxy).PropertyBehavior();
				akismetClient.SubmitHam(comment);
				LastCall.IgnoreArguments();
			}

			using (mocks.Playback())
			{
				Akismet<IFakeComment> service = new Akismet<IFakeComment>(akismetClient, commentConverter);
				service.SubmitGoodFeedback(myComment);
			}
		}

		private static IFakeComment SetupFakeComment(MockRepository mocks, IPAddress ip)
		{
			IFakeComment myComment;
			myComment = mocks.DynamicMock<IFakeComment>();
			SetupResult.For(myComment.AuthorUserAgent).Return("Phil");
			SetupResult.For(myComment.IpAddress).Return(ip);
			return myComment;
		}
	}
}
